use expansion_core::error::Result;
use expansion_core::manifest::ContributeDefinition;
use expansion_core::services::contribution_keyword_manager::{IContributionKeywordImpl, RequestContributionContext};
use expansion_core::services::context_manager::ExpansionContext;
use expansion_core::services::when_eval::ActivationContext;
use expansion_core::services::{IExpansionImplement, PluginPackage};
use expansion_core::system::ExpansionSystem;
use std::any::Any;
use std::sync::{Arc, Mutex};

// --- Mock Implementations ---

#[derive(Debug, Clone)]
struct MockApi { version: String }

// --- Provider Plugin ---
struct ProviderPlugin;
impl IExpansionImplement for ProviderPlugin {
    fn activate(&self, ctx: ExpansionContext) -> Option<Box<dyn Any + Send + Sync>> {
        let keyword_impl = MockKeywordImpl::new();
        ctx.register_contribution_keyword("test_keyword", Box::new(keyword_impl));
        Some(Box::new(MockApi { version: "1.0.0".to_string() }))
    }
    fn deactivate(&self) {}
}
struct ProviderPackage;
impl PluginPackage for ProviderPackage {
    fn manifest_str(&self) -> &'static str {
        include_str!("./provider.json")
    }
    fn implementation(&self) -> Box<dyn IExpansionImplement> {
        Box::new(ProviderPlugin)
    }
}

// --- Consumer Plugin ---
struct ConsumerPlugin;
impl IExpansionImplement for ConsumerPlugin {
    fn activate(&self, ctx: ExpansionContext) -> Option<Box<dyn Any + Send + Sync>> {
        let version = ctx.with_extension("provider", |api: &MockApi| api.version.clone()).unwrap();
        assert_eq!(version, "1.0.0");
        None
    }
    fn deactivate(&self) {}
}
struct ConsumerPackage;
impl PluginPackage for ConsumerPackage {
    fn manifest_str(&self) -> &'static str {
        include_str!("./consumer.json")
    }
    fn implementation(&self) -> Box<dyn IExpansionImplement> {
        Box::new(ConsumerPlugin)
    }
}

// --- Keyword Implementation ---
#[derive(Clone)]
struct MockKeywordImpl {
    pub received: Arc<Mutex<Vec<ContributeDefinition>>>,
}
impl MockKeywordImpl {
    fn new() -> Self {
        Self { received: Arc::new(Mutex::new(Vec::new())) }
    }
}
impl IContributionKeywordImpl for MockKeywordImpl {
    fn request_contribution(&mut self, _ctx: RequestContributionContext, definitions: Vec<ContributeDefinition>) {
        self.received.lock().unwrap().extend(definitions);
    }
    fn request_contribution_point(&mut self, _ctx: RequestContributionContext, _definitions: Vec<expansion_core::manifest::ContributionPointDefinition>) {}
}


#[test]
fn test_plugin_package_system() -> Result<()> {
    // 1. Create a list of plugin packages
    let packages: Vec<Box<dyn PluginPackage>> = vec![
        Box::new(ProviderPackage),
        Box::new(ConsumerPackage),
    ];

    // 2. Create the system from packages
    let system = ExpansionSystem::new(packages)?;

    // 3. Activate
    system.activate("start", &ActivationContext::new())?;

    // Assertions can be more complex, but successful execution proves the flow.
    Ok(())
}
